﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Reflection;
using AGB.Enums;
using AGB.IDemonbuddy;
using AGB.Managerial;
using AGB.Modules.CerebralCortex_;
using AGB.Modules.FrontalLobe_;
using AGB.Modules.FrontalLobe_.CombatBehavior;
using AGB.Modules.FrontalLobe_.VendorRun;
using D3.Pathing;
using Demonbuddy;
using Zeta;
using Zeta.Common;
using Zeta.Common.Plugins;
using Zeta.CommonBot;
using Zeta.CommonBot.Logic;
using Zeta.Internals;
using Zeta.Internals.Actors;
using Zeta.Internals.SNO;
using Zeta.Navigation;
using Zeta.TreeSharp;
using Action = Zeta.TreeSharp.Action;

namespace AGB.Modules
{

    public enum LeaveGameReasons
    {
        Watchdog_death,
        Timeout,
        Run_ended
    }

    public class CerebralCortex : Module
    {
        public CerebralCortex()
        {
            Name = "CerebralCortex";
            Author = "none";
            Version = "0.1.0";
        }

        public int WatchdogExtension = 0;
        public int StartTick = 0;

        public void ClearBlacklist()
        {
            _itemBlackList = new Dictionary<int, BlacklistEntry>();

            /*while (itemBlackList.Count > 0)
            {
                var x = itemBlackList.First();
                itemBlackList[x.Key] = 0;
                itemBlackList.Remove(x.Key);
            }*/
            
        }

        public SarkothStatistics Stats = new SarkothStatistics();

        private Dictionary<int, BlacklistEntry> _itemBlackList = new Dictionary<int, BlacklistEntry>(); 
        private GenericCombat _combatLogic = new GenericCombat();
        private GenericCombat _safeTeleportLogic = new GenericCombat();

        #region FaceBehaviors

        public Composite GenerateOperateEnvironmentBehavior(string target, bool waitForTarget = true, float x = -1,
                                                            float y = -1)
        {
            string _target;
            bool _isDone = false;
            _target = target;

            var myChild = new PrioritySelector();

            CanRunDecoratorDelegate Runner = delegate { return !_isDone; };

            myChild.AddChild(GenerateMoveToObjectBehavior<CachedGizmo>(target));

            if (x > 0)
                myChild.AddChild(new Decorator(delegate
                {
                    if (BotManager.UnitManager.GetObject<CachedGizmo>(_target) ==
                        null)
                    {
                        return true;
                    }

                    return false;
                }, GenerateMoveToPositionBehavior(x, y)));
            myChild.AddChild(GenerateCheckForNpcBehavior<CachedGizmo>(target, waitForTarget));
            myChild.AddChild(_GenerateOperateEnvironmentBehavior(target));

            myChild.AddChild(new Action(delegate { _isDone = true; }));

            return new Decorator(Runner, myChild);
        }

        public Composite GenerateTalkToNpcBehavior(string target, bool waitForTarget = false, float x = -1, float y = -1)
        {
            string _target;
            bool _isDone = false;
            _target = target;

            var myChild = new PrioritySelector();

            CanRunDecoratorDelegate Runner = delegate { return !_isDone; };

            myChild.AddChild(GenerateMoveToObjectBehavior<CachedUnit>(target));

            if (x > 0)
                myChild.AddChild(new Decorator(delegate
                {
                    if (BotManager.UnitManager.GetObject<CachedUnit>(_target) == null)
                    {
                        return true;
                    }

                    return false;
                }, GenerateMoveToPositionBehavior(x, y)));
            myChild.AddChild(GenerateCheckForNpcBehavior<CachedUnit>(target, waitForTarget));
            myChild.AddChild(GenerateInteractWithNpcBehavior(target));

            myChild.AddChild(new Action(delegate
            {

                _isDone = true;
            }));

            return new Decorator(Runner, myChild);
        }

        public Composite GenerateCheckForNpcBehavior<T>(String target, bool waitIfNotExists) where T : CachedObject
        {
            var sequence = new Sequence();
            //sequence.AddChild(new Sleep(200));          
            sequence.AddChild(new Action(delegate
            {
                if (BotManager.UnitManager.GetObject<T>(target) == null)
                {
                    if (waitIfNotExists) return RunStatus.Running;
                    else return RunStatus.Failure;
                }
                if (waitIfNotExists) return RunStatus.Success;
                else return RunStatus.Failure;
            }));
            sequence.AddChild(new WaitContinueMs(1000, rem => false, new ActionAlwaysFail()));
            return sequence;
        }

        public Composite GenerateInteractWithNpcBehavior(String target)
        {
            bool _isFinnished = false;
            string _target = "";

            _target = target;

            CanRunDecoratorDelegate Runner = delegate
            {
                if (_isFinnished)
                    return false;
                var u = BotManager.UnitManager.GetObject<CachedUnit>(target);
                if (u == null)
                    return false;
                if (
                    BotManager.Legs.GetDistance(u.GetPosition().X,
                                                u.GetPosition().Y) > 3)
                    return false;

                return true;
            };

            var seq = new PrioritySelector();

            seq.AddChild(new Action(delegate
            {
                if (BotManager.UnitManager.GetObject<CachedUnit>(target) == null)
                {
                    return RunStatus.Failure;
                }
                BotManager.Face.Interact(target);
                _isFinnished = true;
                return RunStatus.Failure;
            }));
            //seq.AddChild(new Sleep(200));
            seq.AddChild(new WaitContinueMs(1000, rem => false, new ActionAlwaysSucceed()));

            return new Decorator(Runner, seq);
        }

        #endregion

        #region LegBehaviors

        public Composite GenerateMoveToObjectBehavior<T>(String t) where T : CachedObject
        {
            bool _isFinnished = false;
            Path _path = null;
            Point _cur;
            var _target = new Point(int.MaxValue, int.MaxValue);
            Legs legs = BotManager.Legs;

            _cur = new Point(int.MaxValue, int.MaxValue);

            var Runner = new CanRunDecoratorDelegate(context =>
            {
                if (legs.GetDistance(_target.X, _target.Y) < 3 ||
                    _isFinnished ||
                    BotManager.UnitManager.GetObject<T>(t) == null)
                    return false;
                return true;
            });

            var myChild = new PrioritySelector();

            myChild.AddChild(new Decorator(rem => _path == null,
                                           new Action(delegate
                                           {
                                               var u = BotManager.UnitManager.GetObject<T>(t);
                                               _target = new Point((int)u.GetPosition().X,
                                                                   (int)u.GetPosition().Y);

                                               if (u.InLightOfSight()) _path = new Path(ZetaDia.Me.Position.X, ZetaDia.Me.Position.Y, _target.X, _target.Y);
                                               else _path =
                                                   Multiverse.GetCurrentMap().ComputePath(
                                                       u.GetPosition().X, u.GetPosition().Y,
                                                       heurs.Euclidean);

                                               SpeedyAStarNode tmp = _path.GetNextNode();
                                               float[] tmpP = _path.MapToD3Coords(tmp.X, tmp.Y);

                                               _cur = new Point((int)tmpP[0], (int)tmpP[1]);

                                               return RunStatus.Success;
                                           })));

            var distanceCheckDelegate = new CanRunDecoratorDelegate(delegate
            {
                if (_path.Count() == 0)
                    return
                        legs.GetDistance(
                            _path.getCurNodeInD3Coords().X,
                            _path.getCurNodeInD3Coords().Y) >
                        5 && _path.IsValid;
                return
                    legs.GetDistance(
                        _path.getCurNodeInD3Coords().X,
                        _path.getCurNodeInD3Coords().Y) >
                    legs.MinDistDefault && _path.IsValid;
            });

            myChild.AddChild(new Decorator(distanceCheckDelegate,
                                           new Sequence(
                                               new Action(delegate
                                               {
                                                   legs.Walk(_cur.X, _cur.Y);
                                                   return RunStatus.Success;
                                               }),
                /*new Sleep(200)//*/
                                               new WaitContinueMs(200, rem => false, new ActionAlwaysFail())
                                               )));


            myChild.AddChild(new Action(delegate
            {
                if (_path.Count() == 0)
                {
                    _path = null;
                    _isFinnished = true;
                    return (RunStatus.Failure);
                }

                SpeedyAStarNode tmp = _path.GetNextNode();

                float[] tmpP = _path.MapToD3Coords(tmp.X, tmp.Y);

                _cur = new Point((int)tmpP[0], (int)tmpP[1]);

                return (RunStatus.Success);
            }));

            return new Decorator(Runner, myChild);
        }

        public Composite GenerateMoveToPositionBehavior(float x, float y, bool force = false)
        {
            bool _isFinnished = false;
            Path _path = null;
            Point _cur;
            var _target = new Point((int)x, (int)y);
            Legs legs = BotManager.Legs;

            _cur = new Point(int.MaxValue, int.MaxValue);

            var Runner = new CanRunDecoratorDelegate(context =>
            {
                if (legs.GetDistance(_target.X, _target.Y) < 3 ||
                    _isFinnished) return false;
                return true;
            });

            var myChild = new PrioritySelector();

            myChild.AddChild(new Decorator(rem => _path == null,
                                           new Action(delegate
                                           {
                                               /*if (BotManager.Face.HasLineOfSight(new Vector3(_target.X, _target.Y, ZetaDia.Me.Position.Z)))
                                                   _path = new Path(ZetaDia.Me.Position.X, ZetaDia.Me.Position.Y,_target.X,_target.Y);
                                               else */
                                               _path = Multiverse.GetCurrentMap().ComputePath(_target,
                                                                                      heurs.
                                                                                          Euclidean);



                                               SpeedyAStarNode tmp = _path.GetNextNode();
                                               float[] tmpP = _path.MapToD3Coords(tmp.X, tmp.Y);

                                               _cur = new Point((int)tmpP[0], (int)tmpP[1]);

                                               return RunStatus.Success;
                                           })));

            var distanceCheckDelegate = new CanRunDecoratorDelegate(delegate
            {
                if (_path.Count() == 0)
                    return
                        legs.GetDistance(
                            _path.getCurNodeInD3Coords().X,
                            _path.getCurNodeInD3Coords().Y) >
                        5 && _path.IsValid;
                else
                    return
                        legs.GetDistance(
                            _path.getCurNodeInD3Coords().X,
                            _path.getCurNodeInD3Coords().Y) >
                        legs.MinDistDefault && _path.IsValid;
            });

            myChild.AddChild(new Decorator(distanceCheckDelegate,
                                           new Sequence(
                                               new Action(delegate
                                               {
                                                   legs.Walk(_cur.X, _cur.Y);
                                                   return RunStatus.Success;
                                               }),
                //new Sleep(200)
                                               new WaitContinueMs(50, rem => false, new ActionAlwaysFail())
                                               )));


            myChild.AddChild(new Action(delegate
            {
                if (_path.Count() == 0)
                {
                    _path = null;
                    _isFinnished = true;
                    return (RunStatus.Failure);
                }

                SpeedyAStarNode tmp = _path.GetNextNode();

                float[] tmpP = _path.MapToD3Coords(tmp.X, tmp.Y);

                _cur = new Point((int)tmpP[0], (int)tmpP[1]);

                return (RunStatus.Success);
            }));

            return new Decorator(Runner, myChild);
        }

        #endregion

        #region ArmBehaviors

        public Composite GenerateDestroyEnviromentBehavior(String target)
        {
            String _target = target;
            bool _isFinnished = false;

            CanRunDecoratorDelegate Runner = delegate
            {
                if (_isFinnished)
                    return false;

                var u = BotManager.UnitManager.GetObject<CachedGizmo>(_target);

                if (u == null)
                    return false;

                if (
                    BotManager.Legs.GetDistance(u.GetPosition().X,
                                                u.GetPosition().Y) > 5)
                    return false;

                return true;
            };

            var seq = new PrioritySelector();

            seq.AddChild(new Action(delegate
            {
                var _u = BotManager.UnitManager.GetObject<CachedGizmo>(_target);
                if (_u == null) return RunStatus.Failure;

                //Hero.GetSignatureSkill().use(BotManager.UnitManager.GetUnit(_target));
                _isFinnished = true;
                return RunStatus.Failure;
            }));

            //seq.AddChild(new Sleep(200));
            seq.AddChild(new WaitContinueMs(200, rem => false, new ActionAlwaysSucceed()));

            return new Decorator(Runner, seq);
        }

        public Composite _GenerateOperateEnvironmentBehavior(String target)
        {
            bool _isFinnished = false;
            string _target = "";

            _target = target;
            CanRunDecoratorDelegate Runner = delegate
            {
                if (_isFinnished)
                    return false;
                var u = BotManager.UnitManager.GetObject<CachedGizmo>(target);
                if (u == null)
                    return false;
                if (u.getDistance() > 10) return false;
                return true;
            };

            var seq = new PrioritySelector();

            seq.AddChild(new Action(delegate
            {
                if (BotManager.UnitManager.GetObject<CachedGizmo>(target) == null)
                    return RunStatus.Failure;
                BotManager.Face.Operate(target);
                _isFinnished = true;
                return RunStatus.Failure;
            }));

            //seq.AddChild(new Sleep(1000));
            seq.AddChild(new WaitContinueMs(0, rem => false, new ActionAlwaysSucceed()));

            return new Decorator(Runner, seq);
        }

        #endregion

        #region SkillBehavior

        public Composite GenerateBuffBehavior(SNOPower power)
        {
            return new Action(delegate
            {
                if (!ZetaDia.Me.HasBuff(power)) BotManager.Arms.UseSkillSelf(power);
            });
        }

        #endregion

        #region QuestBehavior

        public CanRunDecoratorDelegate ItemExistsDelegate(float range)
        {
            return delegate
            {
                CachedItem item = BotManager.UnitManager.GetClosestMagicItem();
                if (item == null) return false;
                if (item.getDistance() > range) return false;
                return true;
            };
        }

        /*public Composite GenerateVaultSequenceShort(float x, float y)
        {
            Vector3[] vecs = {new Vector3(x, y, -1)};
            return GenerateVaultSequence(vecs);
        }*/

        public Composite GenerateQuestWalk(Vector3 vector, float precision)
        {

            bool done = false;
            Action walk = new Action(delegate(object context)
            {
                if (vector.Distance2D(ZetaDia.Me.Position) < precision)
                {
                    done = true;
                    ZetaDia.Me.UsePower(SNOPower.Walk, vector, ZetaDia.Me.WorldDynamicId);
                    return RunStatus.Failure;       
                }
                ZetaDia.Me.UsePower(SNOPower.Walk, vector, ZetaDia.Me.WorldDynamicId);
                return RunStatus.Success;
            });
            return new Decorator(ret => (!done), walk);

        }

        public Composite GenerateQuestMovementSequence(Vector3[] hops, Vector3 start = default(Vector3), bool waitAtEnd = false)
        {
            if (start == default(Vector3)) start = ZetaDia.Me.Position;

            var myHops = new Queue<Vector3>((Vector3[]) hops.Clone());
            var lastHop = hops[hops.Length-1];
            var currentHop = start;

            bool isDone = false;

            CanRunDecoratorDelegate moveSequence = delegate(object context) { return !isDone; };

            const float precision = 5;


            var moveToNextHop = new Action(delegate(object context)
                                               {
                                                   
                                                      switch (Navigator.MoveTo(currentHop, "QuestMovementHop"))
                                                      {
                                                          case MoveResult.ReachedDestination:
                                                              if (currentHop == lastHop)
                                                              {
                                                                  isDone = true;
                                                                  return RunStatus.Failure;
                                                              }
                                                              currentHop = myHops.Dequeue();
                                                              return RunStatus.Success;
                                                        
                                                      }
                                                   Logging.Write("Moving");
                                                      return RunStatus.Success;
                                                  });


            var MoveSeq = new Sequence(moveToNextHop, new Sleep(200));

            return new Decorator(moveSequence, MoveSeq);
        }

        public Composite GenerateVaultSequence(Vector3[] hops, Vector3 start = default(Vector3), bool waitAtEnd = false)
        {
            if (start == default(Vector3)) start = ZetaDia.Me.Position;

            bool IsDone = false;

            CanRunDecoratorDelegate VaultSequence1 = delegate(object context)
                                                         {
                                                             if (IsDone) return false;
                                                             var anim = ZetaDia.Me.CommonData.AnimationState;
                                                             if (anim != AnimationState.Casting && anim != AnimationState.Running) return true;
                                                             return false;
                                                         };

            PrioritySelector VaultSequence = new PrioritySelector();

            float precision = 20;

            Vector3 lastHop = start;

            VaultSequence.AddChild(new Decorator(ret => !PowerManager.CanCast(SNOPower.DemonHunter_Vault) && PowerManager.CanCast(SNOPower.DemonHunter_Preparation), GenerateBuffBehavior(SNOPower.DemonHunter_Preparation)));


            foreach (var hop in hops)
            {
                Vector3 tmpHop = lastHop;
                VaultSequence.AddChild(new Decorator(delegate(object context)
                {
                    return (tmpHop.Distance2D(ZetaDia.Me.Position) < precision);
                }, GenerateVault(hop)));
                lastHop = hop;
            }

            Sequence _lastHop = new Sequence(new Action(delegate(object context) { IsDone = true; }));
            if (waitAtEnd) _lastHop.AddChild(new Sleep(300));

            VaultSequence.AddChild(new Decorator(delegate(object context)
            {
                return (lastHop.Distance2D(ZetaDia.Me.Position) < precision);
            }, _lastHop));
            //VaultSequence.AddChild(new Sleep(20));
            VaultSequence.AddChild(new ActionAlwaysSucceed());

            return new Decorator(VaultSequence1, VaultSequence);
        }


        public Composite GenerateVault(Vector3 vector, bool useOnce = false)
        {

            bool used = false;
            Action vault = new Action(delegate(object context)
            {
                used = ZetaDia.Me.UsePower(SNOPower.DemonHunter_Vault, vector, ZetaDia.Me.WorldDynamicId);
                return RunStatus.Failure;
            });
            return new Decorator(ret => (!used || !useOnce), vault);

        }

        public Composite GenerateWaitLoadingWorldBehavior()
        {
            return new Decorator(
                ret => ZetaWrap.IsLoadingWorld(),
                new Action(ret => RunStatus.Success));
        }

        public Composite GenerateCreateGameBehavior(Zeta.Act act, GameDifficulty diff, int quest, int step, bool resume, bool _private)
        {
            bool firstTime = true;
            bool done = false;

            var sleepFirst = new Decorator(rem => firstTime, new Sleep(Properties.Settings.Default.GameDelay));

            var createGame = new Action(delegate(object context)
                                            {
                                                firstTime = false;
                                                if (ZetaWrap.IsInGame())
                                                {
                                                    done = true;
                                                    return RunStatus.Failure;
                                                }


                                                if (ZetaWrap.IsLoadingWorld()) return RunStatus.Success;

                                                ZetaDia.Service.Games.CreateGame(act, diff, quest, step, resume,
                                                                                 _private);

                                                return RunStatus.Success;
                                            });

            var creatingGame = new Sequence(sleepFirst,createGame, new Sleep(2000));
            return new Decorator(rem=>!done,creatingGame);
        }


        public Composite GenerateSummonCompanionBehavior(SNOPower power, String name)
        {
            CanRunDecoratorDelegate Runner = delegate(object context)
            {
                var companion = BotManager.UnitManager.GetObject<CachedUnit>(name);
                if (companion == null)
                    return true;
                return false;
            };

            Sequence CompSequence = new Sequence();
            CompSequence.AddChild(GenerateBuffBehavior(power));
            CompSequence.AddChild(new Sleep(200));
            return new Decorator(Runner, CompSequence);
        }

        public static bool _isExiting = false;

        public Composite GenerateExitBehavior()
        {
            bool isExiting = false;

            var seq = new Sequence();
            seq.AddChild(new Action(delegate
            {

                if (ZetaWrap.OutOfGame())
                {
                    _isExiting = false;
                    isExiting = false;
                    BotManager.FrontalLobe.ResetBot();
                    _combatLogic.Reset();
                    _safeTeleportLogic.Reset();
                    
                    return RunStatus.Success;
                }

                if (isExiting) return RunStatus.Success;

                isExiting = true;
                BotMain.TicksPerSecond = 5;
                ZetaDia.Service.Games.LeaveGame();
                StartTick = 0;
                Stats.numberOfRuns++;
                Stats.lastRunEndTick = Environment.TickCount;
                Stats.lastRunGoldEnd = ZetaDia.Me.Inventory.Coinage;

                Logging.Write(Stats.ToString());


                return RunStatus.Success;
            }));

            seq.AddChild(new Sleep(1000));
            return new Decorator(rem=>_isExiting,seq);
        }

        public CanRunDecoratorDelegate QuestMobExists(String name)
        {
            return delegate(object context)
                       {
                           var mob = BotManager.UnitManager.GetObject<CachedUnit>(name);
                           if (BotManager.UnitManager.GetObject<CachedUnit>(name) == null)
                           {
                               return false;
                           }
                           if (mob.InLightOfSight())
                           {
                               return true;
                           } 
                           return false;
                       };
        }


        public bool HasToIdentify(ACDItem item)
        {
            //Important to get semi accurate data
            item.ParseItemTable();
            if (item.Name != "whatiwanttobeidentified") return false;
            /*Insert your logic for what items should be identified here*/
            return true;
        }

        private void IdentifyItem(object ret)
        {
            ZetaDia.Me.Inventory.IdentifyItem(ZetaDia.Me.Inventory.Backpack.First(HasToIdentify).DynamicId);
        }


        public Composite GenerateSarkothQuestBehavior()
        {

            
            _itemBlackList.Clear();
            

           //System.ServiceModel.
            int vendorCounts = 0;
            var QuestBase = new PrioritySelector();

            //Vendoring.ResetStash();
            //Vendoring.DrawStash();

            _combatLogic.SetPriorityTarget("QuillDemon_A_Unique_LootHoarderLeader");

            //_combatLogic.SetPriorityTarget("ZombieFemale_A_TristramQuest");

            int noOfCells = Stats.cellarsFound;

            bool QuestRunning = false;

            Vector3[] vecs = {
                                 new Vector3(1997.905f, 2625.585f, 31.08125f), 
                                 new Vector3(2010.517f, 2600.299f, 27.09998f), 
                                 new Vector3(2027.154f, 2576.183f, 27.1f), 
                                 new Vector3(2046.485f, 2542.631f, 27.1f)
                             };

            Vector3[] vecs2 = {
                                  new Vector3(2064.686f, 2518.781f, 27.1f),
                                  new Vector3(2090,2497,27.1f), 
                                  new Vector3(2063.614f, 2480.202f, 28.70861f)
                              };

            var PreCellar = new PrioritySelector();

            var InCellar = new PrioritySelector();

            var MidVaultCellarCheck = new PrioritySelector();

            

            MidVaultCellarCheck.AddChild(new Decorator(MobsExistDelegate(20), new Inverter(_safeTeleportLogic.GenerateCombatBehavior(20))));
            MidVaultCellarCheck.AddChild(new Decorator(ItemExistsDelegate(20), GenerateLootBehavior()));
            MidVaultCellarCheck.AddChild(GenerateEndGameProcedure());

            

            GroupComposite VendorRun;
            if (AGB.Properties.Settings.Default.Towrun) VendorRun =
                new Decorator(rem => (ZetaWrap.ForceVendoring || ZetaWrap.NeedsRepair() || Vendoring.IsVendoring),
                new PrioritySelector(
                    new Decorator(rem => ZetaWrap.IsInGame(), new Decorator(MobsExistDelegate(20), new Inverter(_safeTeleportLogic.GenerateCombatBehavior(20)))),
                    new Vendoring(),
                    new Action(delegate(object context)
                                       {
                                           //Logging.Write("Finnished Townrun " + ZetaWrap.ForceVendoring + " " + ZetaWrap.NeedsRepair() + " " + Vendoring.IsVendoring);
                                           ZetaWrap.ForceVendoring = false;
                                       })));
            else
            {
                VendorRun = new Sequence();
                VendorRun.AddChild(new HookExecutor("VendorRun"));
                VendorRun.AddChild(new Action(delegate(object context)
                                                  {
                                                      StartTick += 1000;
                                                      return RunStatus.Success;
                                                  }));

            }


            PreCellar.AddChild(GenerateVaultSequence(vecs, new Vector3(1991.747f, 2653.501f, 39.43713f)));
            PreCellar.AddChild(new Action(delegate(object context) { QuestRunning = true; return RunStatus.Failure; }));
            PreCellar.AddChild(new Decorator(delegate(object context)
            {
                var giz = BotManager.UnitManager.GetObject<CachedGizmo>("g_Portal_Square_Blue");
                if (giz == null) return true;
                if (noOfCells == Stats.cellarsFound) Stats.cellarsFound++;
                return false;
            }, MidVaultCellarCheck));

            PreCellar.AddChild(GenerateVaultSequence(vecs2, new Vector3(2046.485f, 2542.631f, 27.1f), true));
            PreCellar.AddChild(_GenerateOperateEnvironmentBehavior("g_Portal_Square_Blue"));
            Vector3[] vectors2 = { new Vector3(108, 159, 2), new Vector3(122.443f, 133.4221f, 0.1f) };

            InCellar.AddChild(GenerateVaultSequence(vectors2, new Vector3(73.52956f, 160.2407f, 1.707417f)));
            InCellar.AddChild(GenerateSummonCompanionBehavior(SNOPower.DemonHunter_Companion, "DH_Companion_Ferret"));
            InCellar.AddChild(new Decorator(MobsExistDelegate(200), new Inverter(_combatLogic.GenerateCombatBehavior(200))));
            InCellar.AddChild(GenerateVault(new Vector3(120, 114, 2), true));
            InCellar.AddChild(new Decorator(ItemExistsDelegate(40), GenerateLootBehavior()));
            

            QuestBase.AddChild(_GenerateUIWatchdogBehavior());

            QuestBase.AddChild(GenerateExitBehavior());

            QuestBase.AddChild(GenerateCreateGameBehavior(Act.A1, GameDifficulty.Inferno, (int)Quests.A1_The_Legacy_of_Cain, 51, true, true));

            

            QuestBase.AddChild(GenerateStartQuestBehavior());

            QuestBase.AddChild(GenerateWatchdogBehavior(AGB.Properties.Settings.Default.WatchDogDelay));

            QuestBase.AddChild(VendorRun);
            //QuestBase.AddChild(new HookExecutor("VendorRun"));

            QuestBase.AddChild(new Decorator(InAreaDelegate(71150), PreCellar));

            QuestBase.AddChild(new Decorator(InAreaDelegate(106746), InCellar));

            QuestBase.AddChild(new Decorator(context => QuestRunning, GenerateEndGameProcedure()));

            /*Vector3[] vectorsMovement = {
                                            new Vector3(2971.25f,2861.25f,23.94533f),
                                            new Vector3(2939.056f,2802.099f,24.04533f),
                                            new Vector3(2870.291f,2824.47f,24.04532f),
                                            new Vector3(2842.797f,2930.845f,24.04533f), 
                                            new Vector3(2842.797f,2930.845f,24.04533f), 
                                            new Vector3(2693.932f,2856.612f,11.41776f), 
                                            new Vector3(2596.014f,2879.835f,27.15202f),
                                            new Vector3(2441.471f,2875.465f,27.1f),
                                            new Vector3(2402.602f,2794.396f,27.1f),
                                            new Vector3(2332.888f,2714.268f,27.1f),
                                            new Vector3(2318.771f,2602.014f,27.1f),
                                            new Vector3(2317.483f,2519.335f,27.1f),
                                            new Vector3(2217.205f,2493.336f,27.1f),
                                            new Vector3(2113.425f,2514.682f,27.1f),
                                            new Vector3(2045.14f,2536.382f,27.1f),
                                            new Vector3(1997.449f,2599.635f,27.10007f),
                                            new Vector3(1996.384f,2676.24f,40.15685f),
                                            new Vector3(2016.413f,2768.564f,40.15685f),
                                            //new Vector3(2958.531f,2807.299f,24.04533f),
                                            //new Vector3(2946.355f,2804.161f,24.04533f) 
                                        };

            //QuestBase.AddChild(new Action(delegate(object context) { Multiverse.GetCurrentMap().DrawMap(0); }));
            //QuestBase.AddChild(GenerateMoveToPositionBehavior(2946.355f, 2804.161f));
            //QuestBase.AddChild(new Decorator(QuestMobExists("ZombieFemale_A_TristramQuest"),_combatLogic.GenerateCombatBehavior(200)));
            //QuestBase.AddChild(GenerateQuestMovementSequence(vectorsMovement, new Vector3(2971.25f, 2861.25f, 23.94533f)));*/

           /* Vector3[] queenVectors = {
                                         new Vector3(2973.015f, 2849.312f, 24.04533f),
                                         new Vector3(2812.37f, 2932.389f, 24.04533f),
                                         new Vector3(2646.703f, 2860.688f, 11.96796f),
                                         new Vector3(2466.383f, 2853.162f, 27.1f),
                                         new Vector3(2343.013f, 2721.048f, 27.1f),
                                         new Vector3(2314.597f, 2543.089f, 27.1f),
                                         new Vector3(2135.121f, 2521.347f, 27.1f),
                                         new Vector3(1995.116f, 2637.278f, 34.8913f)
                                     };

            QuestBase.AddChild(GenerateQuestMovementSequence(queenVectors, new Vector3(2971.25f, 2861.25f, 23.94533f)));

            /*Vector3 lastPoint = default(Vector3);

            QuestBase.AddChild(new Action(delegate(object context)
                                              {
                                                  if (lastPoint == default(Vector3))
                                                  {
                                                      lastPoint = ZetaDia.Me.Position;
                                                      Logging.Write(lastPoint.ToString());
                                                      return;
                                                  }

                                                  float dist = lastPoint.Distance2D(ZetaDia.Me.Position);


                                                  if (dist > 180 && dist < 200)
                                                  {
                                                      lastPoint = ZetaDia.Me.Position;
                                                      Logging.Write(lastPoint.ToString());
                                                  }
                                              }));*/

            return QuestBase;
        }



        public Composite GenerateStartQuestBehavior()
        {
            return new Action(delegate(object context)
            {

                if (StartTick == 0)
                {
                    Stats.lastRunStartTick = Environment.TickCount;
                    Stats.lastRunGoldStart = ZetaDia.Me.Inventory.Coinage;
                    StartTick = Environment.TickCount;
                }
                return RunStatus.Failure;

            });
        }

        public Composite GenerateEndQuestBehavior()
        {
            return new Action(delegate(object context)
            {
                StartTick = 0;
                return RunStatus.Failure;

            });
        }

        public Composite GenerateEndGameProcedure()
        {
            PrioritySelector endGame = new PrioritySelector();
            endGame.AddChild(GenerateTownPortalBehavior());
            endGame.AddChild(GenerateExitGameBehavior(LeaveGameReasons.Run_ended));
            return endGame;
        }

        public Composite GenerateUiWatchdogBehavior()
        {
            CanRunDecoratorDelegate ErrorMessageClick = delegate(object context)
            {
                Zeta.Internals.UIElement ui = null;
                return
                    (Zeta.Internals.UIElement.IsValidElement(
                        0x4CC93A73A58BAFFF) &&
                     (ui =
                      Zeta.Internals.UIElement.FromHash(
                          0x4CC93A73A58BAFFF)) != null);
            };
            return new Decorator(ErrorMessageClick, _GenerateUIWatchdogBehavior());
        }

        public Composite GenerateExitGameBehavior(LeaveGameReasons reason)
        {
            return new Action(delegate(object context)
                                  {
                                      if (reason == LeaveGameReasons.Watchdog_death)
                                      {
                                          Stats.deaths++;
                                          if (Stats.deaths > Properties.Settings.Default.KillswitchCount && Properties.Settings.Default.Killswitch)
                                          {
                                              Logging.Write("We died soo many times i lost count");
                                              Environment.Exit(0);
                                          }
                                        Logging.Write("Ending Game: We Died :(");
                                      }
                                      if (reason == LeaveGameReasons.Timeout)
                                      {
                                          Stats.stucks++;
                                          Logging.Write("Ending Game: Stuck");
                                      }
                                      if (reason == LeaveGameReasons.Run_ended)
                                      {
                                          Logging.Write("Ending Game: Finnished Run");
                                      }
                                      _isExiting = true;
                                  });
        }

        public Composite GenerateWatchdogBehavior(int timeout)
        {
            //Error 0xB4433DA3F648A992

            Sequence Watchdog = new Sequence();

            WatchdogExtension = 0;

            PrioritySelector checkForDead = new PrioritySelector();

            Action deadCheck = new Action(delegate(object context)
                                           {
                                               if (!ZetaWrap.IsInGame()) return RunStatus.Success;
                                               if (ZetaWrap.IsDead()) return RunStatus.Failure;
                                               return RunStatus.Success;
                                           });
            

            checkForDead.AddChild(deadCheck);
            checkForDead.AddChild(GenerateExitGameBehavior(LeaveGameReasons.Watchdog_death));

            PrioritySelector checkForTimeout = new PrioritySelector();

            Action timeoutCheck = new Action(delegate(object context)
                                                 {
                                                     if (StartTick + timeout + WatchdogExtension < Environment.TickCount) return RunStatus.Failure;
                                                     return RunStatus.Success;
                                                 });

            checkForTimeout.AddChild(timeoutCheck);
            checkForTimeout.AddChild(GenerateExitGameBehavior(LeaveGameReasons.Timeout));


            Watchdog.AddChild(checkForDead);
            Watchdog.AddChild(checkForTimeout);

            return new Decorator(EveryXMsDelegate(5000), Watchdog);
        }

        public CanRunDecoratorDelegate EveryXMsDelegate(int ms)
        {
            int myTimeout = ms;
            int myTimer = Environment.TickCount - ms;
            return delegate(object context)
            {
                //Logging.Write(myTimeout+"+"+myTimer+" <? "+Environment.TickCount);
                if (myTimer + myTimeout < Environment.TickCount)
                {
                    myTimer = Environment.TickCount;
                    return true;
                }
                return false;
            };
        }

        public Composite _GenerateUIWatchdogBehavior()
        {
            return new Decorator(EveryXMsDelegate(1000), new Action(delegate(object context)
            {
                Zeta.Internals.UIElement ui = null; if (Zeta.Internals.UIElement.IsValidElement(0x4CC93A73A58BAFFF) && (ui = Zeta.Internals.UIElement.FromHash(0x4CC93A73A58BAFFF)) != null)
                {
                    if (ui.IsVisible)
                    {
                        Zeta.Internals.UIElement Button = null; if (Zeta.Internals.UIElement.IsValidElement(0xB4433DA3F648A992) && (Button = Zeta.Internals.UIElement.FromHash(0xB4433DA3F648A992)) != null)
                        {
                            if (Button.IsVisible) { Button.Click(); if (Zeta.Internals.UIElement.IsValidElement(0x51A3923949DC80B7) && (Button = Zeta.Internals.UIElement.FromHash(0x51A3923949DC80B7)) != null) { if (Button.IsVisible && Button.IsEnabled) { Button.Click(); } } }
                        }
                    }
                } return RunStatus.Failure;
            }));
        }


        public Composite GenerateForcedMovementBehavior(float x, float y)
        {
            bool _isFinnished = false;

            var distanceCheckDelegate = new CanRunDecoratorDelegate(delegate
            {
                return (BotManager.Legs.GetDistance(x, y) > 5);
            });


            var Runner = new CanRunDecoratorDelegate(context =>
            {
                if (BotManager.Legs.GetDistance(x, y) < 3 ||
                    _isFinnished) return false;
                return true;
            });

            var selector = new PrioritySelector();
            var moveSequence = new Sequence();
            moveSequence.AddChild(new Decorator(distanceCheckDelegate,
                                           new Sequence(
                                               new Action(delegate
                                               {
                                                   BotManager.Legs.Walk(x, y);
                                                   Logging.Write("Ended Forced move");
                                                   return RunStatus.Success;
                                               }),
                                               new WaitContinueMs(50, rem => false, new ActionAlwaysFail())
                                               )));

            selector.AddChild(moveSequence);
            selector.AddChild(new Action(delegate
            {

                _isFinnished = true;
                return (RunStatus.Failure);
            }));
            return new Decorator(Runner, selector);
        }

        public CanRunDecoratorDelegate MobsExistDelegate(float range)
        {
            return delegate
            {
                CachedUnit hostile = BotManager.UnitManager.GetClosestHostile();
                if (hostile == null) return false;
                if (hostile.getDistance() > range) return false;
                return true;
            };
        }

        public CanRunDecoratorDelegate InAreaDelegate(int area)
        {
            return delegate
            {
                if (ZetaDia.CurrentWorldId != area || ZetaWrap.IsInTown()) return false;
                return true;
            };
        }

        public CanRunDecoratorDelegate MobNearDelegate()
        {
            return delegate
            {
                CachedUnit hostile = BotManager.UnitManager.GetClosestHostile();
                if (hostile == null) return false;
                if (hostile.getDistance() > 8) return false;
                return true;
            };
        }

        public CanRunDecoratorDelegate CellarExistDelegate()
        {
            return delegate
            {
                if (BotManager.UnitManager.GetObject<CachedGizmo>("g_Portal_Square_Blue") != null)
                    return true;
                return false;
            };
        }

        public CanRunDecoratorDelegate InTownDelegate()
        {
            return delegate { return ZetaWrap.IsInTown(); };
        }

        #endregion

        public void PrintStatistics()
        {

        }

        #region UIBehavior



        #endregion

        #region TownBehavior

        public string GetVendorNpc()
        {
            return "Miner";
        }

        /*public Composite GenerateTownBehavior()
        {
            var TownBehavior = new PrioritySelector();
            TownBehavior.AddChild(GenerateTownPortalBehavior());
            TownBehavior.AddChild(new HookExecutor());
            return TownBehavior;
        }

        public Composite GenerateVendorBehavior()
        {
            CanRunDecoratorDelegate NeedVendoring = delegate(object context)
                                                     {
                                                         return true;
                                                     };

            String vendor = GetVendorNpc();

            PrioritySelector Behavior = new PrioritySelector();

            Behavior.AddChild(GenerateTalkToNpcBehavior(vendor));
            Behavior.AddChild(GenerateInitItemManagerBehavior());
            Behavior.AddChild(GenerateRepairBehavior());
            Behavior.AddChild(GenerateSellBehavior());
            Behavior.AddChild(GenerateTalkToNpcBehavior("PT_Blacksmith_RepairShortcut", false,2938, 2845));
            Behavior.AddChild(GenerateSalvageBehavior());

            return new Decorator(NeedVendoring, Behavior);
           
        }

        public Composite GenerateRepairBehavior()
        {
            bool fireOnce = false;
            CanRunDecoratorDelegate FireOnce = delegate(object context)
                                                   {
                                                       if (!fireOnce)
                                                       {
                                                           fireOnce = true;
                                                           return true;
                                                       }
                                                       return false;
                                                   };
            return new Decorator(FireOnce,new Action(delegate(object context) { ZetaDia.Me.Inventory.RepairEquippedItems(); }));
        }

        public Composite GenerateInitItemManagerBehavior()
        {
            bool fireOnce = false;
            CanRunDecoratorDelegate FireOnce = delegate(object context)
            {
                if (!fireOnce)
                {
                    fireOnce = true;
                    return true;
                }
                return false;
            };
            return new Decorator(FireOnce, new Action(delegate(object context) { ItemManager.Initialize();
            ItemManager.Refresh();}));
        }


        public Composite GenerateSellBehavior()
        {
            bool fireOnce = false;
            CanRunDecoratorDelegate FireOnce = delegate(object context)
            {
                if (!fireOnce)
                {
                    fireOnce = true;
                    return true;
                }
                return false;
            };
            return new Decorator(FireOnce, new Action(delegate(object context) { ItemManager.SellItems(); }));
        }

        public Composite GenerateSalvageBehavior()
        {
            bool fireOnce = false;
            CanRunDecoratorDelegate FireOnce = delegate(object context)
            {
                if (!fireOnce)
                {
                    fireOnce = true;
                    return true;
                }
                return false;
            };
            return new Decorator(FireOnce, new Action(delegate(object context) { ItemManager.SalvageItems(); }));
        }

        public Composite GenerateStashingBehavior()
        {
            bool fireOnce = false;
            CanRunDecoratorDelegate FireOnce = delegate(object context)
            {
                if (!fireOnce)
                {
                    fireOnce = true;
                    return true;
                }
                return false;
            };
            return new Decorator(FireOnce, new Action(delegate(object context) { ItemManager.StashItems(); }));
        }*/

        public Composite GenerateTownPortalBehavior()
        {
            CanRunDecoratorDelegate InTown = delegate
            {
                if (ZetaDia.Me == null) return false;
                if (!ZetaWrap.IsInTown() && ZetaDia.Me.CommonData.AnimationState != AnimationState.Channeling)
                    return true;
                return false;
            };

            var pSequence = new Sequence();
            var PortHome = new Action(delegate
            {
                ZetaDia.Me.UseTownPortal();
                return RunStatus.Success;
            });
            pSequence.AddChild(PortHome);
            pSequence.AddChild(new Sleep(4000));
            return new Decorator(InTown, PortHome);
        }

        #endregion

        #region LootBehavior

        public Composite GenerateMoveToNextItemBehavior()
        {
            var Behavior = new PrioritySelector();

            var MoveToItem = new Action(delegate
            {
                var item = BotManager.UnitManager.GetClosestMagicItem();
                if (item == null) return;
                if (item.GetNativeObject() == null) return;
                Vector3 position =
                    BotManager.UnitManager.GetClosestMagicItem().GetPosition();
                BotManager.Legs.Walk(position.X, position.Y);
            });

            Behavior.AddChild(MoveToItem);
            Behavior.AddChild(new Sleep(100));
            return Behavior;
        }

        public Composite GenerateVendoringCheck()
        {
            return new Action(context => Vendoring.IsVendoring ? RunStatus.Success : RunStatus.Failure);
        }
        public Composite GenerateLootBehavior()
        {
            var LootBehavior = new PrioritySelector();
            LootBehavior.AddChild(GenerateCheckForItemsBehavior(200));
            LootBehavior.AddChild(new Decorator(ItemInRangeDelegate(4), GenerateLootItemBehavior()));
            LootBehavior.AddChild(GenerateMoveToNextItemBehavior());
            LootBehavior.AddChild(new ActionAlwaysSucceed());
            return new Decorator(rem => !Vendoring.IsVendoring, LootBehavior);
        }

        public CanRunDecoratorDelegate ItemInRangeDelegate(float range)
        {
            return delegate
            {
                CachedItem target = BotManager.UnitManager.GetClosestMagicItem();
                if (target == null) return false;
                if (target.GetNativeObject() == null) return false;
                if (target.getDistance() < range && target.InLightOfSight())
                    return true;
                return false;
            };
        }

        public Composite GenerateCheckForItemsBehavior(float range)
        {
            var CheckForItemsInRange = new Action(delegate
            {
                CachedItem target =
                    BotManager.UnitManager.GetClosestMagicItem();
                if (target == null) return RunStatus.Success;
                if (target.GetNativeObject() == null) return RunStatus.Success;
                if (target.getDistance() >= range) return RunStatus.Success;
                return RunStatus.Failure;
            });
            var ret = new PrioritySelector(CheckForItemsInRange, new Sleep(100));
            return ret;
        }

        public class BlacklistEntry
        {
            public int Count = 0;
            public long Timer = Environment.TickCount;
        }

        public void BlacklistItem(int guid)
        {
            if (!_itemBlackList.ContainsKey(guid)) _itemBlackList.Add(guid,new BlacklistEntry());

            if (_itemBlackList[guid].Timer+500 < Environment.TickCount)
            {
                _itemBlackList[guid].Timer = Environment.TickCount;
                _itemBlackList[guid].Count++;
            }
                

            if (_itemBlackList[guid].Count > 1)
            {
                ZetaWrap.ForceVendoring = true;
                _itemBlackList.Clear();
            }
        }

        public Composite GenerateLootItemBehavior()
        {
            var Loot = new Action(delegate
            {
                CachedItem target = BotManager.UnitManager.GetClosestMagicItem();
                if (target != null)
                    if (target.GetNativeObject() != null)
                    {
                        var iguid = target.GetNativeObject().CommonData.DynamicId;
                        target.Interact();
                        BlacklistItem(iguid);
                    }

            });

            var lootSequence = new Sequence(Loot, new Sleep(50));
            return new Decorator(rem => (true), lootSequence);
        }

        #endregion
    }
}